console: Port Multi Console driver to AArch32
authorDaniel Boulby <[email protected]>
Wed, 19 Sep 2018 12:55:47 +0000 (13:55 +0100)
committerDaniel Boulby <[email protected]>
Fri, 21 Sep 2018 12:04:07 +0000 (13:04 +0100)
The old driver is now in deprecated_console.S, in a similar way to the
AArch64 driver.

Change-Id: Ib57209c322576c451d466d7406a94adbf01ab8fd
Signed-off-by: Daniel Boulby <[email protected]>
Makefile
drivers/console/aarch32/console.S
drivers/console/aarch32/deprecated_console.S [new file with mode: 0644]
drivers/console/aarch32/multi_console.S [new file with mode: 0644]

index 9dc8a42208d95437519ba04a7fe828cc5f021ca6..5aa8db967781c41baa85dee73181f16c9b312681 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -416,12 +416,6 @@ ifeq ($(HW_ASSISTED_COHERENCY)-$(USE_COHERENT_MEM),1-1)
 $(error USE_COHERENT_MEM cannot be enabled with HW_ASSISTED_COHERENCY)
 endif
 
-ifneq ($(MULTI_CONSOLE_API), 0)
-    ifeq (${ARCH},aarch32)
-        $(error "Error: MULTI_CONSOLE_API is not supported for AArch32")
-    endif
-endif
-
 #For now, BL2_IN_XIP_MEM is only supported when BL2_AT_EL3 is 1.
 ifeq ($(BL2_AT_EL3)-$(BL2_IN_XIP_MEM),0-1)
 $(error "BL2_IN_XIP_MEM is only supported when BL2_AT_EL3 is enabled")
index a3c654609a89a8f9482ff88e20d75cbfa1618f94..f909609469a849a0667ebf0d925b42b039a28e95 100644 (file)
@@ -3,104 +3,9 @@
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
-#include <asm_macros.S>
 
-       .globl  console_init
-       .globl  console_uninit
-       .globl  console_putc
-       .globl  console_getc
-       .globl  console_flush
-
-       /*
-        *  The console base is in the data section and not in .bss
-        *  even though it is zero-init. In particular, this allows
-        *  the console functions to start using this variable before
-        *  the runtime memory is initialized for images which do not
-        *  need to copy the .data section from ROM to RAM.
-        */
-.section .data.console_base ; .align 2
-       console_base: .word 0x0
-
-       /* -----------------------------------------------
-        * int console_init(uintptr_t base_addr,
-        * unsigned int uart_clk, unsigned int baud_rate)
-        * Function to initialize the console without a
-        * C Runtime to print debug information. It saves
-        * the console base to the data section.
-        * In: r0 - console base address
-        *     r1 - Uart clock in Hz
-        *     r2 - Baud rate
-        * out: return 1 on success else 0 on error
-        * Clobber list : r1 - r3
-        * -----------------------------------------------
-        */
-func console_init
-       /* Check the input base address */
-       cmp     r0, #0
-       beq     init_fail
-       ldr     r3, =console_base
-       str     r0, [r3]
-       b       console_core_init
-init_fail:
-       bx      lr
-endfunc console_init
-
-       /* -----------------------------------------------
-        * void console_uninit(void)
-        * Function to finish the use of console driver.
-        * It sets the console_base as NULL so that any
-        * further invocation of `console_putc` or
-        * `console_getc` APIs would return error.
-        * -----------------------------------------------
-        */
-func console_uninit
-       mov     r0, #0
-       ldr     r3, =console_base
-       str     r0, [r3]
-       bx      lr
-endfunc console_uninit
-
-       /* ---------------------------------------------
-        * int console_putc(int c)
-        * Function to output a character over the
-        * console. It returns the character printed on
-        * success or -1 on error.
-        * In : r0 - character to be printed
-        * Out : return -1 on error else return character.
-        * Clobber list : r1, r2
-        * ---------------------------------------------
-        */
-func console_putc
-       ldr     r2, =console_base
-       ldr     r1, [r2]
-       b       console_core_putc
-endfunc console_putc
-
-       /* ---------------------------------------------
-        * int console_getc(void)
-        * Function to get a character from the console.
-        * It returns the character grabbed on success
-        * or -1 on error.
-        * Clobber list : r0, r1
-        * ---------------------------------------------
-        */
-func console_getc
-       ldr     r1, =console_base
-       ldr     r0, [r1]
-       b       console_core_getc
-endfunc console_getc
-
-       /* ---------------------------------------------
-        * int console_flush(void)
-        * Function to force a write of all buffered
-        * data that hasn't been output. It returns 0
-        * upon successful completion, otherwise it
-        * returns -1.
-        * Clobber list : r0, r1
-        * ---------------------------------------------
-        */
-func console_flush
-       ldr     r1, =console_base
-       ldr     r0, [r1]
-       b       console_core_flush
-endfunc console_flush
+ #if MULTI_CONSOLE_API
+ #include "multi_console.S"
+ #else
+ #include "deprecated_console.S"
+ #endif
diff --git a/drivers/console/aarch32/deprecated_console.S b/drivers/console/aarch32/deprecated_console.S
new file mode 100644 (file)
index 0000000..f7e3c4f
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+
+/*
+ * This is the common console core code for the deprecated single-console API.
+ * New platforms should set MULTI_CONSOLE_API=1 and not use this file.
+ */
+#warning "Using deprecated console implementation. Please migrate to MULTI_CONSOLE_API"
+
+       .globl  console_init
+       .globl  console_uninit
+       .globl  console_putc
+       .globl  console_getc
+       .globl  console_flush
+
+       /*
+        *  The console base is in the data section and not in .bss
+        *  even though it is zero-init. In particular, this allows
+        *  the console functions to start using this variable before
+        *  the runtime memory is initialized for images which do not
+        *  need to copy the .data section from ROM to RAM.
+        */
+.section .data.console_base ; .align 2
+       console_base: .word 0x0
+
+       /* -----------------------------------------------
+        * int console_init(uintptr_t base_addr,
+        * unsigned int uart_clk, unsigned int baud_rate)
+        * Function to initialize the console without a
+        * C Runtime to print debug information. It saves
+        * the console base to the data section.
+        * In: r0 - console base address
+        *     r1 - Uart clock in Hz
+        *     r2 - Baud rate
+        * out: return 1 on success else 0 on error
+        * Clobber list : r1 - r3
+        * -----------------------------------------------
+        */
+func console_init
+       /* Check the input base address */
+       cmp     r0, #0
+       beq     init_fail
+       ldr     r3, =console_base
+       str     r0, [r3]
+       b       console_core_init
+init_fail:
+       bx      lr
+endfunc console_init
+
+       /* -----------------------------------------------
+        * void console_uninit(void)
+        * Function to finish the use of console driver.
+        * It sets the console_base as NULL so that any
+        * further invocation of `console_putc` or
+        * `console_getc` APIs would return error.
+        * -----------------------------------------------
+        */
+func console_uninit
+       mov     r0, #0
+       ldr     r3, =console_base
+       str     r0, [r3]
+       bx      lr
+endfunc console_uninit
+
+       /* ---------------------------------------------
+        * int console_putc(int c)
+        * Function to output a character over the
+        * console. It returns the character printed on
+        * success or -1 on error.
+        * In : r0 - character to be printed
+        * Out : return -1 on error else return character.
+        * Clobber list : r1, r2
+        * ---------------------------------------------
+        */
+func console_putc
+       ldr     r2, =console_base
+       ldr     r1, [r2]
+       b       console_core_putc
+endfunc console_putc
+
+       /* ---------------------------------------------
+        * int console_getc(void)
+        * Function to get a character from the console.
+        * It returns the character grabbed on success
+        * or -1 on error.
+        * Clobber list : r0, r1
+        * ---------------------------------------------
+        */
+func console_getc
+       ldr     r1, =console_base
+       ldr     r0, [r1]
+       b       console_core_getc
+endfunc console_getc
+
+       /* ---------------------------------------------
+        * int console_flush(void)
+        * Function to force a write of all buffered
+        * data that hasn't been output. It returns 0
+        * upon successful completion, otherwise it
+        * returns -1.
+        * Clobber list : r0, r1
+        * ---------------------------------------------
+        */
+func console_flush
+       ldr     r1, =console_base
+       ldr     r0, [r1]
+       b       console_core_flush
+endfunc console_flush
diff --git a/drivers/console/aarch32/multi_console.S b/drivers/console/aarch32/multi_console.S
new file mode 100644 (file)
index 0000000..e23b20e
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console.h>
+
+       .globl  console_register
+       .globl  console_unregister
+       .globl  console_is_registered
+       .globl  console_set_scope
+       .globl  console_switch_state
+       .globl  console_putc
+       .globl  console_getc
+       .globl  console_flush
+
+       /*
+        *  The console list pointer is in the data section and not in
+        *  .bss even though it is zero-init. In particular, this allows
+        *  the console functions to start using this variable before
+        *  the runtime memory is initialized for images which do not
+        *  need to copy the .data section from ROM to RAM.
+        */
+.section .data.console_list ; .align 2
+       console_list: .word 0x0
+.section .data.console_state ; .align 0
+       console_state: .byte CONSOLE_FLAG_BOOT
+
+       /* -----------------------------------------------
+        * int console_register(console_t *console)
+        * Function to insert a new console structure into
+        * the console list. Should usually be called by
+        * console_<driver>_register implementations. The
+        * data structure passed will be taken over by the
+        * console framework and *MUST* be allocated in
+        * persistent memory (e.g. the data section).
+        * In : r0 - address of console_t structure
+        * Out: r0 - Always 1 (for easier tail calling)
+        * Clobber list: r0, r1
+        * -----------------------------------------------
+        */
+func console_register
+       push    {r6,  lr}
+#if ENABLE_ASSERTIONS
+       /* Assert that r0 isn't a NULL pointer */
+       cmp     r0, #0
+       ASM_ASSERT(ne)
+       /* Assert that the struct isn't in the stack */
+       ldr     r1, =__STACKS_START__
+       cmp     r0, r1
+       blo     not_on_stack
+       ldr     r1, =__STACKS_END__
+       cmp     r0, r1
+       ASM_ASSERT(hs)
+not_on_stack:
+       /* Assert that this struct isn't in the list */
+       mov     r1, r0 /* Preserve r0 and lr */
+       bl      console_is_registered
+       cmp     r0, #0
+       ASM_ASSERT(eq)
+       mov     r0, r1
+#endif /* ENABLE_ASSERTIONS */
+       ldr     r6, =console_list
+       ldr     r1, [r6]        /* R1 = first struct in list */
+       str     r0, [r6]        /* list head = new console */
+       str     r1, [r0, #CONSOLE_T_NEXT]       /* new console next ptr = R1 */
+       mov     r0, #1
+       pop     {r6, pc}
+endfunc console_register
+
+       /* -----------------------------------------------
+        * int console_unregister(console_t *console)
+        * Function to find a specific console in the list
+        * of currently active consoles and remove it.
+        * In: r0 - address of console_t struct to remove
+        * Out: r0 - removed address, or NULL if not found
+        * Clobber list: r0, r1
+        * -----------------------------------------------
+        */
+func console_unregister
+#if ENABLE_ASSERTIONS
+       /* Assert that r0 isn't a NULL pointer */
+       cmp     r0, #0
+       ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+       push    {r6}
+       ldr     r6, =console_list               /* R6 = ptr to first struct */
+       ldr     r1, [r6]                        /* R1 = first struct */
+
+unregister_loop:
+       cmp     r1, #0
+       beq     unregister_not_found
+       cmp     r0, r1
+       beq     unregister_found
+       ldr     r6, [r6]                        /* R6 = next ptr of struct */
+       ldr     r1, [r6]                        /* R1 = next struct */
+       b       unregister_loop
+
+unregister_found:
+       ldr     r1, [r1]                        /* R1 = next struct */
+       str     r1, [r6]                        /* prev->next = cur->next */
+       pop     {r6}
+       bx      lr
+
+unregister_not_found:
+       mov     r0, #0                          /* return NULL if not found */
+       pop     {r6}
+       bx      lr
+endfunc console_unregister
+
+       /* -----------------------------------------------
+        * int console_is_registered(console_t *console)
+        * Function to detect if a specific console is
+        * registered or not.
+        * In: r0 - address of console_t struct to remove
+        * Out: r0 - 1 if it is registered, 0 if not.
+        * Clobber list: r0
+        * -----------------------------------------------
+        */
+func console_is_registered
+#if ENABLE_ASSERTIONS
+       /* Assert that r0 isn't a NULL pointer */
+       cmp     r0, #0
+       ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+       push    {r6}
+       ldr     r6, =console_list
+       ldr     r6, [r6]        /* R6 = first console struct */
+check_registered_loop:
+       cmp     r6, #0                  /* Check if end of list */
+       beq     console_not_registered
+       cmp     r0, r6          /* Check if the pointers are different */
+       beq     console_registered
+       ldr     r6, [r6, #CONSOLE_T_NEXT]       /* Get pointer to next struct */
+       b       check_registered_loop
+console_not_registered:
+       mov     r0, #0
+       pop     {r6}
+       bx      lr
+console_registered:
+       mov     r0, #1
+       pop     {r6}
+       bx      lr
+endfunc console_is_registered
+
+       /* -----------------------------------------------
+        * void console_switch_state(unsigned int new_state)
+        * Function to switch the current console state.
+        * The console state determines which of the
+        * registered consoles are actually used at a time.
+        * In : r0 - global console state to move to
+        * Clobber list: r0, r1
+        * -----------------------------------------------
+        */
+func console_switch_state
+       ldr     r1, =console_state
+       strb    r0, [r1]
+       bx      lr
+endfunc console_switch_state
+
+       /* -----------------------------------------------
+        * void console_set_scope(console_t *console,
+        *                       unsigned int scope)
+        * Function to update the states that a given console
+        * may be active in.
+        * In : r0 - pointer to console_t struct
+        *    : r1 - new active state mask
+        * Clobber list: r0, r1, r2
+        * -----------------------------------------------
+        */
+func console_set_scope
+#if ENABLE_ASSERTIONS
+       ands    r2, r1, #~CONSOLE_FLAG_SCOPE_MASK
+       ASM_ASSERT(eq)
+#endif /* ENABLE_ASSERTIONS */
+       ldr     r2, [r0, #CONSOLE_T_FLAGS]
+       and     r2, r2, #~CONSOLE_FLAG_SCOPE_MASK
+       orr     r2, r2, r1
+       str     r2, [r0, #CONSOLE_T_FLAGS]
+       bx      lr
+endfunc console_set_scope
+
+       /* ---------------------------------------------
+        * int console_putc(int c)
+        * Function to output a character. Calls all
+        * active console's putc() handlers in succession.
+        * In : r0 - character to be printed
+        * Out: r0 - printed character on success, or < 0
+                    if at least one console had an error
+        * Clobber list : r0, r1, r2
+        * ---------------------------------------------
+        */
+func console_putc
+       push    {r4-r6, lr}
+       mov     r5, #ERROR_NO_VALID_CONSOLE     /* R5 = current return value */
+       mov     r4, r0                          /* R4 = character to print */
+       ldr     r6, =console_list
+       ldr     r6, [r6]        /* R6 = first console struct */
+
+putc_loop:
+       cmp     r6, #0
+       beq     putc_done
+       ldr     r1, =console_state
+       ldrb    r1, [r1]
+       ldr     r2, [r6, #CONSOLE_T_FLAGS]
+       tst     r1, r2
+       beq     putc_continue
+       ldr     r2, [r6, #CONSOLE_T_PUTC]
+       cmp     r2, #0
+       beq     putc_continue
+       mov     r0, r4
+       mov     r1, r6
+       blx     r2
+       cmp     r5, #ERROR_NO_VALID_CONSOLE     /* update R5 if it's NOVALID */
+       cmpne   r0, #0                          /* else update it if R0 < 0 */
+       movlt   r5, r0
+putc_continue:
+       ldr     r6, [r6]                        /* R6 = next struct */
+       b       putc_loop
+
+putc_done:
+       mov     r0, r5
+       pop     {r4-r6, pc}
+endfunc console_putc
+
+       /* ---------------------------------------------
+        * int console_getc(void)
+        * Function to get a character from any console.
+        * Keeps looping through all consoles' getc()
+        * handlers until one of them returns a
+        * character, then stops iterating and returns
+        * that character to the caller. Will stop looping
+        * if all active consoles report real errors
+        * (other than just not having a char available).
+        * Out : r0 - read character, or < 0 on error
+        * Clobber list : r0, r1
+        * ---------------------------------------------
+        */
+func console_getc
+       push    {r5-r6, lr}
+getc_try_again:
+       mov     r5, #ERROR_NO_VALID_CONSOLE     /* R5 = current return value */
+       ldr     r6, =console_list
+       ldr     r6, [r6]                        /* R6 = first console struct */
+       cmp     r6, #0
+       bne     getc_loop
+       mov     r0, r5                          /* If no consoles registered */
+       pop     {r5-r6, pc}                     /* return immediately. */
+
+getc_loop:
+       ldr     r0, =console_state
+       ldrb    r0, [r0]
+       ldr     r1, [r6, #CONSOLE_T_FLAGS]
+       tst     r0, r1
+       beq     getc_continue
+       ldr     r1, [r6, #CONSOLE_T_GETC]
+       cmp     r1, #0
+       beq     getc_continue
+       mov     r0, r6
+       blx     r1
+       cmp     r0, #0                          /* if R0 >= 0: return */
+       bge     getc_found
+       cmp     r5, #ERROR_NO_PENDING_CHAR      /* may update R5 (NOCHAR has */
+       movne   r5, r0                          /* precedence vs real errors) */
+getc_continue:
+       ldr     r6, [r6]                        /* R6 = next struct */
+       cmp     r6, #0
+       bne     getc_loop
+       cmp     r5, #ERROR_NO_PENDING_CHAR      /* Keep scanning if at least */
+       beq     getc_try_again                  /* one console returns NOCHAR */
+       mov     r0, r5
+
+getc_found:
+       pop     {r5-r6, pc}
+endfunc console_getc
+
+       /* ---------------------------------------------
+        * int console_flush(void)
+        * Function to force a write of all buffered
+        * data that hasn't been output. Calls all
+        * console's flush() handlers in succession.
+        * Out: r0 - 0 on success, < 0 if at least one error
+        * Clobber list : r0, r1, r2
+        * ---------------------------------------------
+        */
+func console_flush
+       push    {r5-r6, lr}
+       mov     r5, #ERROR_NO_VALID_CONSOLE     /* R5 = current return value */
+       ldr     r6, =console_list
+       ldr     r6, [r6]                        /* R6 = first console struct */
+
+flush_loop:
+       cmp     r6, #0
+       beq     flush_done
+       ldr     r1, =console_state
+       ldrb    r1, [r1]
+       ldr     r2, [r6, #CONSOLE_T_FLAGS]
+       tst     r1, r2
+       beq     flush_continue
+       ldr     r1, [r6, #CONSOLE_T_FLUSH]
+       cmp     r1, #0
+       beq     flush_continue
+       mov     r0, r6
+       blx     r1
+       cmp     r5, #ERROR_NO_VALID_CONSOLE     /* update R5 if it's NOVALID */
+       cmpne   r0, #0                          /* else update it if R0 < 0 */
+       movlt   r5, r0
+flush_continue:
+       ldr     r6, [r6]                        /* R6 = next struct */
+       b       flush_loop
+
+flush_done:
+       mov     r0, r5
+       pop     {r5-r6, pc}
+endfunc console_flush